﻿using System;

using Microsoft.SPOT.IO;

using mfLogger;

using OST.Shared;
using OST.Shared.Interfaces;
using OST.Shared.Extensions;
using System.Threading;
using Microsoft.SPOT;


namespace OST.Persistence
{
    public class RemoveableMediaStorageProvider : IStorageProvider
    {
        #region Consts&Fields
        /// <summary>
        /// name of the target sd volume 
        /// </summary>
        const string C_STR_DEFAULT_VOLUME_NAME = "SD";

        #endregion

        #region CTOR// Singleton
        //http://msdn.microsoft.com/en-us/library/ff650316.aspx
        //--> not thread-safe, with dynamic initialization

        private static RemoveableMediaStorageProvider _instance = null;

        private RemoveableMediaStorageProvider()
        {
            RootDirectory = String.Empty;
        }

        public static RemoveableMediaStorageProvider Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new RemoveableMediaStorageProvider();
                }
                return _instance;
            }
        }

        #endregion

        #region Properties


        /// <summary>
        /// wrapper-property 4 logging
        /// </summary>
        public ILoggerAppender Logger
        {
            get
            {
                return mfLogger.mfLogger.Instance;
            }
        }

        #endregion

        #region Methods

        private void RemovableMedia_Insert(object sender, MediaEventArgs e)
        {
            if (e.Volume.Name != C_STR_DEFAULT_VOLUME_NAME)
            {
                Logger.Debug("invalid media inserted '" + e.Volume.Name + "'");
                return;
            }

            Logger.Debug("RemovableMedia_Insert executing, new Volume " + e.Volume.Name
                + " (Totalsize=" + e.Volume.TotalSize + ";Freespace=" + e.Volume.TotalFreeSpace + ")");
            
            UpdateRootDirectory();

            Logger.Info("RemovableMedia_Insert executed");
        }


        private void RemovableMedia_Eject(object sender, MediaEventArgs e)
        {
            //RemovableMedia_Insert is raised two times 1. Volu
            if (e.Volume.Name != C_STR_DEFAULT_VOLUME_NAME)
            {
                Logger.Debug("invalid media ejected '" + e.Volume.Name + "'");
                return;
            }

            Logger.Debug("RemovableMedia_Eject executing, Volume " + e.Volume.Name);

            UpdateRootDirectory();
            Debug.GC(true);

            Logger.Info("RemovableMedia_Eject executed, Volume " + e.Volume.Name);
        }

        private void UpdateRootDirectory()
        {
            try
            {
                SetRootDirectory(new VolumeInfo(C_STR_DEFAULT_VOLUME_NAME).RootDirectory);
            }
            catch
            {
                SetRootDirectory(string.Empty);
            }
        }

        private void SetRootDirectory(string rootDirectory)
        {
            RootDirectory = rootDirectory;

            if (RootDirectory.IsNullOrEmpty()) IsStorageConntected = false;
            else IsStorageConntected = true;

            OnNotifyPropertyChanged("IsStorageConntected", IsStorageConntected);
        }

        #endregion

        #region IPersistentStorage

        public string RootDirectory
        {
            get;
            private set;
        }

        public bool IsStorageConntected
        {
            get;
            private set;
        }

        public void Initialize()
        {
            if (IsStorageConntected)
            {
                Logger.Debug(GetType()+"Initialize(): storage already connected");
                return;
            }

            UpdateRootDirectory();

            //avoid first insert-event, by sleep (maybe there's a better way)
            Thread.Sleep(300);

            RemovableMedia.Insert += RemovableMedia_Insert;
            RemovableMedia.Eject += RemovableMedia_Eject;

            if (RootDirectory == string.Empty)
            {
                Logger.Error("no media inserted");
            }
        }

        #endregion

        #region INotifyPropertyChanged

        /// <summary>
        /// notifies clients over changes in puplic properties
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnNotifyPropertyChanged(String propertyName, object newValue)
        {
            if (PropertyChanged != null && !propertyName.IsNullOrEmpty())
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName, newValue));
            }
        }

        #endregion
    }
}
